{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "cedf868076a2"
   },
   "source": [
    "##### Copyright 2020 The Cirq Developers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cellView": "form",
    "id": "906e07f6e562"
   },
   "outputs": [],
   "source": [
    "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "# https://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "8bbd73c03ac2"
   },
   "source": [
    "# Transforming circuits"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "25eb74f260d6"
   },
   "source": [
    "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://www.example.org/cirq/transform\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />View on QuantumLib</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/quantumlib/Cirq/blob/master/docs/transform.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Run in Google Colab</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://github.com/quantumlib/Cirq/blob/master/docs/transform.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />View source on GitHub</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a href=\"https://storage.googleapis.com/tensorflow_docs/Cirq/docs/transform.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Download notebook</a>\n",
    "  </td>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "846b32703c5c"
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    import cirq\n",
    "except ImportError:\n",
    "    print(\"installing cirq...\")\n",
    "    !pip install --quiet cirq\n",
    "    print(\"installed cirq.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9d3d49b9ca2a"
   },
   "source": [
    "## Circuit optimizers\n",
    "\n",
    "Cirq comes with the concept of an optimizer.  Optimizers will pass over a circuit and perform tasks that will modify the circuit in place.  These can be used to transform a circuit in specific ways, such as combining single-qubit gates, commuting Z gates through the circuit, or readying the circuit for certain hardware or gate set configurations.\n",
    "\n",
    "Optimizers will have a function `optimize_circuit()` that can be used to perform this optimization.  Here is a simple example that removes empty moments:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "e2893a817870"
   },
   "outputs": [],
   "source": [
    "import cirq\n",
    "c=cirq.Circuit()\n",
    "c.append(cirq.Moment([]))\n",
    "c.append(cirq.Moment([cirq.X(cirq.GridQubit(1,1))]))\n",
    "c.append(cirq.Moment([]))\n",
    "print(f'Before optimization, Circuit has {len(c)} moments')\n",
    "\n",
    "cirq.DropEmptyMoments().optimize_circuit(circuit=c)\n",
    "print(f'After optimization, Circuit has {len(c)} moments')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "861ea1ada088"
   },
   "source": [
    "Optimizers that come with cirq can be found in the `cirq.optimizers` package.\n",
    "\n",
    "A few notable examples are:\n",
    "\n",
    "*   **ConvertToCzAndSingleGates**: Attempts to convert a circuit into CZ gates and single qubit gates.  This uses gate's unitary and decompose methods to transform them into CZ + single qubit gates.\n",
    "*   **DropEmptyMoments** / **DropNegligible**:  Removes moments that are empty or have very small effects, respectively.\n",
    "*   **EjectPhasedPaulis**: Pushes X, Y, and PhasedX gates towards the end of the circuit, potentially absorbing Z gates and modifying gates along the way.\n",
    "*   **EjectZ**:  Pushes Z gates towards the end of the circuit, potentially adjusting phases of gates that they pass through.\n",
    "*   **ExpandComposite**:  Uses `cirq.decompose` to expand composite gates.\n",
    "*   **MergeInteractions**:  Combines series of adjacent one and two-qubit gates acting on a pair of qubits.\n",
    "*   **MergeSingleQubitGates**:  Combines series of adjacent unitary 1-qubit operations\n",
    "*   **SynchronizeTerminalMeasurements**:  Moves all measurements in a circuit to the final moment if possible.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "c6c7e3ed57ba"
   },
   "source": [
    "### Create your own optimizers\n",
    "\n",
    "You can create your own optimizers to transform and modify circuits to fit hardware, gate sets, or other requirements.  Optimizers can also be used to generate noise.  See [noise](noise.ipynb) for details.\n",
    "\n",
    "You can do this by implementing the function `optimize_circuit`.\n",
    "\n",
    "If your optimizer is a local optimizer and depends primarily on operator being examined, you can alternatively inherit `cirq.PointOptimizer` and implement the function `optimization_at(self, circuit, index, op)` that optimizes a single operation.\n",
    "\n",
    "Below is an example of implementing a simple `PointOptimizer` that removes measurements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "e046ef24c70e"
   },
   "outputs": [],
   "source": [
    "class RemoveMeasurements(cirq.PointOptimizer):\n",
    "    def optimization_at(self, circuit: cirq.Circuit, index: int, op: cirq.Operation):\n",
    "      if isinstance(op.gate, cirq.MeasurementGate):\n",
    "        return cirq.PointOptimizationSummary(clear_span=1,\n",
    "                                             new_operations=[],\n",
    "                                             clear_qubits=op.qubits)\n",
    "      else:\n",
    "        return None\n",
    "\n",
    "q=cirq.LineQubit(0)\n",
    "c=cirq.Circuit(cirq.X(q), cirq.measure(q))\n",
    "print('Before optimization')\n",
    "print(c)\n",
    "RemoveMeasurements().optimize_circuit(c)\n",
    "print('After optimization')\n",
    "print(c)\n"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "transform.ipynb",
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
